#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#define MAX_LENGTH 1024
#define BUFFER_LENGTH 2048

typedef int (*RCALLBACK) (int fd);

int epfd = -1;

struct conn_item 
{
    int fd;
	char rbuffer[BUFFER_LENGTH];
	int rlen;
	char wbuffer[BUFFER_LENGTH];
	int wlen;
    union 
    {
        RCALLBACK accept_callback;
        RCALLBACK recv_callback;
    } recv_t;
    RCALLBACK send_callback;
};

struct conn_item connectlist[MAX_LENGTH] = {0};


// sockfd
int accept_cb(int fd);
// clientfd
int recv_cb(int fd);
int send_cb(int fd);
int set_event(int fd, int event, int flag);
int http_request(struct conn_item* connection);
int http_response(struct conn_item* connection);




int accept_cb(int fd)
{
    struct sockaddr_in client_addr;
    socklen_t len = sizeof(client_addr);
    int clientfd = accept(fd, (struct sockaddr*)&client_addr, &len);
    if(-1 == clientfd)
    {
        perror("accept:");
        exit(-1);
    }
    set_event(clientfd, EPOLLIN, 1);
	printf("clientfd: %d\n", clientfd);
    connectlist[clientfd].fd = clientfd;
    memset(connectlist[clientfd].rbuffer, 0, BUFFER_LENGTH);
	memset(connectlist[clientfd].wbuffer, 0, BUFFER_LENGTH);
	connectlist[clientfd].rlen = 0;
	connectlist[clientfd].wlen = 0;
	connectlist[clientfd].recv_t.recv_callback = recv_cb;
    connectlist[clientfd].send_callback = send_cb;
    return clientfd;
}


int recv_cb(int fd)
{
    char *buffer = connectlist[fd].rbuffer;
    int idx = connectlist[fd].rlen;
    ssize_t  count = recv(fd, buffer + idx, BUFFER_LENGTH - idx, 0);
    if(0 == count)
    {
        printf("disconnected\n");
        epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
        close(fd);
        return -1;
    }
    connectlist[fd].rlen += count;
    

    // 将可读事件改为可写事件
    /*
        当我们读完此fd后我们要关注这个fd是否可写,事件触发一次做一次操作
    */
#if 0 // 将接受到的数据写入wbuffer中作为返回数据
	memcpy(connectlist[fd].wbuffer, connectlist[fd].rbuffer, connectlist[fd].rlen);
	connectlist[fd].wlen = connectlist[fd].rlen;
#else
	http_request(&connectlist[fd]);
	http_response(&connectlist[fd]);
#endif
    set_event(fd, EPOLLOUT, 0);

    return count;
}

int send_cb(int fd)
{
    char *buffer = connectlist[fd].wbuffer;
    int idx = connectlist[fd].wlen;
    int count = send(fd, buffer, idx, 0);

    struct epoll_event ev;
    set_event(fd, EPOLLIN, 0);

    return count;
}

int set_event(int fd, int event, int flag)
{
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = event;
    if(flag) // 1 新增 0 修改
        epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
    else 
        epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);
    return 1;
}

int http_request(struct conn_item* connection)
{
	return 0;
}

int http_response(struct conn_item* connection)
{
	
	int filefd = open("./index.html", O_RDONLY);
	struct stat fstat_buf;
	fstat(filefd, &fstat_buf);

	connection->wlen = sprintf(
		connection->wbuffer,
		"HTTP/1.1 200 OK\r\n"
		"Accept-Ranges: bytes\r\n"
		"Content-Length: %ld\r\n"
		"Content-Type: text/html\r\n"
		"Date: Sat, 06 Aug 2023 13:16:45 GMT\r\n\r\n"
	, fstat_buf.st_size);
	printf("count: %d\n", fstat_buf.st_size);
	int count = read(filefd, connection->wbuffer + connection->wlen, BUFFER_LENGTH - connection->wlen);
	connection->wlen += count;
	return count;
}

int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == sockfd)
    {
        perror("socket:");
        exit(-1);
    }
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(4396);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    int ret = bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(-1 == ret)
    {
        perror("bind:");
        close(sockfd);
        exit(-1);
    }

    if(-1 == listen(sockfd, 10))
    {
        perror("listen:");
        close(sockfd);
        exit(-1);
    }
    connectlist[sockfd].fd = sockfd;
    connectlist[sockfd].recv_t.accept_callback = accept_cb;

    epfd = epoll_create(1);
    if(-1 == epfd)
    {
        perror("epoll_create:");
        exit(-1);
    }

    struct epoll_event events[MAX_LENGTH];
    // 
    set_event(sockfd, EPOLLIN, 1);

    while(1)
    {
        int nready = epoll_wait(epfd, events, MAX_LENGTH, -1);
        int i = 0;
        for(; i < nready; i ++)
        {
            int connfd = events[i].data.fd;
            if (events[i].events & EPOLLIN)
            {
                int count = connectlist[connfd].recv_t.recv_callback(connfd);
                printf("recv <--: buffer: %s\n", connectlist[connfd].rbuffer);

            } 
            else if (events[i].events & EPOLLOUT)
            {
                int count = connectlist[connfd].send_callback(connfd);
                //printf("send -->: buffer: %s\n", connectlist[connfd].wbuffer);
            }
        }
    }
    exit(0);
}
